package com.kinyx.framework.file;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;

import com.kinyx.framework.Configs;
import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.exception.KRuntimeException;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 读取工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KReader {

	@ReturnNotNull
	private static void closeInputStream(@CanNull final InputStream inputStream) {
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (final IOException e) {} // ignore this
		}
	}

	/**
	 * 读取字符串结果
	 * @param reader 读取类对象
	 * @return 字符串结果
	 */
	@ReturnNotNull
	@Throws(at = "KReader.read(InputStream, String)", value = "IOException", when = "Reader.read()")
	public static String read(@CanNotNull final Reader reader) {
		try {
			final StringBuilder sb = new StringBuilder();
			for (int c = reader.read(); c != -1; c = reader.read()) { sb.append((char) c); }
			return sb.toString();
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (final IOException e) {} // ignore this
			}
		}
	}

	/**
	 * 从流中读取字符串结果
	 * @param inputStream 输入流
	 * @param charset 字符集
	 * @return 字符串结果
	 */
	@ReturnNotNull
	@Throws(at = "KReader.read(InputStream, String)", value = "UnsupportedEncodingException", when = "new InputStreamReader(InputStream, String)")
	@Throws(at = "KReader.read(InputStream, String)", value = "IOException", when = "InputStreamReader.read()")
	public static String read(@CanNotNull final InputStream inputStream, @CanNull(defaultValue = "Configs.default_KReader_charset") final String charset) {
		if (charset == null) { return read(inputStream, Configs.default_KReader_charset); }
		InputStreamReader isr = null;
		try {
			isr = new InputStreamReader(inputStream, charset);
		} catch (final UnsupportedEncodingException e) {
			closeInputStream(inputStream);
			throw new KRuntimeException(e);
		}

		try {
			final StringBuilder sb = new StringBuilder();
			for (int c = isr.read(); c != -1; c = isr.read()) { sb.append((char) c); }
			return sb.toString();
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		} finally {
			if (isr != null) {
				try {
					isr.close();
				} catch (final IOException e) {} // ignore this
			}
			closeInputStream(inputStream);
		}
	}

	/**
	 * 从流中读取字节数组结果
	 * @param inputStream 输入流
	 * @return 字节数组结果
	 */
	@ReturnNotNull
	@Throws(at = "KReader.readBytes(InputStream)", value = "IOException", when = "InputStream.available()")
	@Throws(at = "KReader.readBytes(InputStream)", value = "IOException", when = "InputStream.read(byte[])")
	public static byte[] readBytes(@CanNotNull final InputStream inputStream) {
		int available;
		try {
			available = inputStream.available();
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		}
		try {
			final byte[] bytes = new byte[available];
			for (int bytesRead = inputStream.read(bytes); bytesRead != -1; bytesRead = inputStream.read(bytes)) {}
			return bytes;
		} catch (final IOException e) {
			throw new KRuntimeException(e);
		} finally {
			closeInputStream(inputStream);
		}
	}

}
